using System;
using System.IO;
using System.Net;
using System.Xml;
using System.Data;
using System.Text;
using System.Web;
using System.Web.Services;
using System.Security.Cryptography;
using System.Configuration;
using NopSolutions.NopCommerce.Common.Utils;
using NopSolutions.NopCommerce.BusinessLogic.Orders;

namespace MediaCoders.NopCommerce.Code.MultiSafePay
{
    /// <summary>
    /// MultiSafePay communication handler
    /// </summary>
    public class MultiSafePay
    {
        #region Structs

        /// <summary>
        /// Struct to hold vendor related data
        /// </summary>
        public struct MerchantStruct
        {
            public bool TestAccount;
            public string AccountId;
            public string SiteId;
            public string SiteCode;
            public string NotificationUrl;
            public string RedirectUrl;
            public string ReturnUrl;
            public string CancelUrl;
        }

        /// <summary>
        /// Struct to hold customer related data
        /// </summary>
        public struct CustomerStruct
        {
            public string Locale;
            public string IpAddress;
            public string ForwardedIp;
            public string Firstname;
            public string Lastname;
            public string Address1;
            public string Address2;
            public string Housenumber;
            public string Zipcode;
            public string City;
            public string State;
            public string Country;
            public string Phone;
            public string Email;
        }

        /// <summary>
        /// Struct to hold transaction related data
        /// </summary>
        public struct TransactionStruct
        {
            public string ID;
            public string Currency;
            public string Amount;
            public string Description;
            public string Var1;
            public string Var2;
            public string Var3;
            public string Items;
        }

        #endregion  

        #region Fields

        public MerchantStruct Merchant = new MerchantStruct();
        public CustomerStruct Customer = new CustomerStruct();
        public TransactionStruct Transaction = new TransactionStruct();

        #endregion

        #region Properties

        public string ErrorCode { get; set; }
        public string ErrorDescription { get; set; }

        #endregion

        #region Private Methods

        private string XmlEscape(string content)
        {
            return System.Web.HttpUtility.HtmlEncode(content);
        }

        #endregion

        #region Constructor

        public MultiSafePay(Order order)
        {
            LoadSettings(order);
        }

        #endregion

        #region Private Methods

        private void LoadSettings(Order order)
        {
            Merchant.NotificationUrl = CommonHelper.GetStoreLocation(false) + "multisafepayreturn.aspx?s=2&o=" + order.OrderId;
            Merchant.ReturnUrl = CommonHelper.GetStoreLocation(false) + "checkoutcompleted.aspx";
            Merchant.CancelUrl = CommonHelper.GetStoreLocation(false) + "multisafepayreturn.aspx?s=1&o=" + order.OrderId;
            Merchant.TestAccount = MultiSafePayPaymentSettings.TestAccount;
            Merchant.AccountId = MultiSafePayPaymentSettings.AccountId;
            Merchant.SiteId = MultiSafePayPaymentSettings.SiteId;
            Merchant.SiteCode = MultiSafePayPaymentSettings.SiteCode;
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Starts the payment transaction at MultiSafePay
        /// </summary>
        /// <returns></returns>
        public string StartTransaction()
        {
            MD5CryptoServiceProvider md5Hasher = new MD5CryptoServiceProvider();
            byte[] hashedBytes = null;
            UTF8Encoding encoder = new UTF8Encoding();
            string signature = null;
            string outgoingTRANSaction = null;

            string ipAddress = null;
            string forwardedIp = null;

            ipAddress = System.Web.HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];
            forwardedIp = System.Web.HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];

            hashedBytes = md5Hasher.ComputeHash(encoder.GetBytes(Transaction.Amount + Transaction.Currency + Merchant.AccountId + Merchant.SiteId + Transaction.ID));
            signature = BitConverter.ToString(hashedBytes).Replace("-", "").ToLower();

            //create this programatically?
            outgoingTRANSaction = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + "\n";
            outgoingTRANSaction += "<redirecttransaction>" + "\n";
            outgoingTRANSaction += "  <merchant>" + "\n";
            outgoingTRANSaction += "    <account>" + XmlEscape(Merchant.AccountId) + "</account>" + "\n";
            outgoingTRANSaction += "    <site_id>" + XmlEscape(Merchant.SiteId) + "</site_id>" + "\n";
            outgoingTRANSaction += "    <site_secure_code>" + XmlEscape(Merchant.SiteCode) + "</site_secure_code>" + "\n";
            outgoingTRANSaction += "    <notification_url>" + XmlEscape(Merchant.NotificationUrl) + "</notification_url>" + "\n";
            outgoingTRANSaction += "    <redirect_url>" + XmlEscape(Merchant.RedirectUrl) + "</redirect_url>" + "\n";
            outgoingTRANSaction += "    <cancel_url>" + XmlEscape(Merchant.CancelUrl) + "</cancel_url>" + "\n";
            outgoingTRANSaction += "  </merchant>" + "\n";
            outgoingTRANSaction += "  <customer>" + "\n";
            outgoingTRANSaction += "    <locale>" + XmlEscape(Customer.Locale) + "</locale>" + "\n";
            outgoingTRANSaction += "    <ipaddress>" + ipAddress + "</ipaddress>" + "\n";
            outgoingTRANSaction += "    <forwardedip>" + forwardedIp + "</forwardedip>" + "\n";
            outgoingTRANSaction += "    <firstname>" + XmlEscape(Customer.Firstname) + "</firstname>" + "\n";
            outgoingTRANSaction += "    <lastname>" + XmlEscape(Customer.Lastname) + "</lastname>" + "\n";
            outgoingTRANSaction += "    <address1>" + XmlEscape(Customer.Address1) + "</address1>" + "\n";
            outgoingTRANSaction += "    <address2>" + XmlEscape(Customer.Address2) + "</address2>" + "\n";
            outgoingTRANSaction += "    <housenumber>" + XmlEscape(Customer.Housenumber) + "</housenumber>" + "\n";
            outgoingTRANSaction += "    <zipcode>" + XmlEscape(Customer.Zipcode) + "</zipcode>" + "\n";
            outgoingTRANSaction += "    <city>" + XmlEscape(Customer.City) + "</city>" + "\n";
            outgoingTRANSaction += "    <state>" + XmlEscape(Customer.State) + "</state>" + "\n";
            outgoingTRANSaction += "    <country>" + XmlEscape(Customer.Country) + "</country>" + "\n";
            outgoingTRANSaction += "    <phone>" + XmlEscape(Customer.Phone) + "</phone>" + "\n";
            outgoingTRANSaction += "    <email>" + XmlEscape(Customer.Email) + "</email>" + "\n";
            outgoingTRANSaction += "  </customer>" + "\n";
            outgoingTRANSaction += "  <transaction>" + "\n";
            outgoingTRANSaction += "    <id>" + XmlEscape(Transaction.ID) + "</id>" + "\n";
            outgoingTRANSaction += "    <currency>" + XmlEscape(Transaction.Currency) + "</currency>" + "\n";
            outgoingTRANSaction += "    <amount>" + XmlEscape(Transaction.Amount) + "</amount>" + "\n";
            outgoingTRANSaction += "    <description>" + XmlEscape(Transaction.Description) + "</description>" + "\n";
            outgoingTRANSaction += "    <var1>" + XmlEscape(Transaction.Var1) + "</var1>" + "\n";
            outgoingTRANSaction += "    <var2>" + XmlEscape(Transaction.Var2) + "</var2>" + "\n";
            outgoingTRANSaction += "    <var3>" + XmlEscape(Transaction.Var3) + "</var3>" + "\n";
            outgoingTRANSaction += "    <items>" + XmlEscape(Transaction.Items) + "</items>" + "\n";
            outgoingTRANSaction += "    <manual>false</manual>" + "\n";
            outgoingTRANSaction += "  </transaction>" + "\n";
            outgoingTRANSaction += "  <signature>" + signature + "</signature>" + "\n";
            outgoingTRANSaction += "</redirecttransaction>" + "\n";

            string apiURl = null;
            if (Merchant.TestAccount)
            {
                apiURl = "https://testapi.multisafepay.com/ewx/";
            }
            else
            {
                apiURl = "https://api.multisafepay.com/ewx/";
            }

            System.Net.HttpWebRequest httpWebRequest = (HttpWebRequest)System.Net.HttpWebRequest.Create(apiURl);
            httpWebRequest.Method = "POST";
            httpWebRequest.ContentLength = System.Text.Encoding.UTF8.GetByteCount(outgoingTRANSaction);
            httpWebRequest.ContentType = "application/x-www-form-urlencoded";

            StreamWriter streamWriter = new System.IO.StreamWriter(httpWebRequest.GetRequestStream());
            streamWriter.Write(outgoingTRANSaction);
            streamWriter.Close();

            System.Net.HttpWebResponse httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse();
            StreamReader streamReader = new System.IO.StreamReader(httpWebResponse.GetResponseStream());
            string stringResult = streamReader.ReadToEnd();
            string xmlstring = stringResult;
            System.Xml.XmlDocument xd = new System.Xml.XmlDocument();
            xd.LoadXml(xmlstring);

            System.Xml.XmlElement root = xd.DocumentElement;
            string result = root.Attributes.GetNamedItem("result").Value;

            if (result == "ok")
            {
                string paymentUrl = xd.SelectSingleNode("/redirecttransaction/transaction/payment_url").InnerText;
                return paymentUrl;
            }
            else
            {
                ErrorCode = xd.SelectSingleNode("/redirecttransaction/error/code").InnerText;
                ErrorDescription = xd.SelectSingleNode("/redirecttransaction/error/description").InnerText;
                return "";

            }
        }

        /// <summary>
        /// Gets the status of a transaction at MultiSafePay
        /// </summary>
        /// <returns></returns>
        public string GetStatus()
        {
            string outgoingTRANSaction = null;

            outgoingTRANSaction = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + "\n";
            outgoingTRANSaction += "<status>" + "\n";
            outgoingTRANSaction += "  <merchant>" + "\n";
            outgoingTRANSaction += "    <account>" + XmlEscape(Merchant.AccountId) + "</account>" + "\n";
            outgoingTRANSaction += "    <site_id>" + XmlEscape(Merchant.SiteId) + "</site_id>" + "\n";
            outgoingTRANSaction += "    <site_secure_code>" + XmlEscape(Merchant.SiteCode) + "</site_secure_code>" + "\n";
            outgoingTRANSaction += "  </merchant>" + "\n";
            outgoingTRANSaction += "  <transaction>" + "\n";
            outgoingTRANSaction += "    <id>" + XmlEscape(Transaction.ID) + "</id>" + "\n";
            outgoingTRANSaction += "  </transaction>" + "\n";
            outgoingTRANSaction += "</status>" + "\n";

            string apiURl = null;
            if (Merchant.TestAccount)
            {
                apiURl = "https://testapi.multisafepay.com/ewx/";
            }
            else
            {
                apiURl = "https://api.multisafepay.com/ewx/";
            }

            System.Net.HttpWebRequest httpWebRequest = (HttpWebRequest)System.Net.HttpWebRequest.Create(apiURl);
            httpWebRequest.Method = "POST";
            httpWebRequest.ContentLength = System.Text.Encoding.UTF8.GetByteCount(outgoingTRANSaction);
            httpWebRequest.ContentType = "application/x-www-form-urlencoded";

            StreamWriter streamWriter = new System.IO.StreamWriter(httpWebRequest.GetRequestStream());
            streamWriter.Write(outgoingTRANSaction);
            streamWriter.Close();

            System.Net.HttpWebResponse httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse();
            StreamReader streamReader = new System.IO.StreamReader(httpWebResponse.GetResponseStream());
            string stringResult = streamReader.ReadToEnd();
            string xmlstring = stringResult;
            System.Xml.XmlDocument xd = new System.Xml.XmlDocument();
            xd.LoadXml(xmlstring);

            System.Xml.XmlElement root = xd.DocumentElement;
            string result = root.Attributes.GetNamedItem("result").Value;

            if (result == "ok")
            {
                string status = xd.SelectSingleNode("/status/ewallet/status").InnerText;
                return status;
            }
            else
            {
                ErrorCode = xd.SelectSingleNode("/status/error/code").InnerText;
                ErrorDescription = xd.SelectSingleNode("/status/error/description").InnerText;
                return "";

            }
        }

        #endregion
    }
}